﻿package com.tomvian.twodee.common.actions 
{
	import flash.display.DisplayObject;
	import flash.display.DisplayObjectContainer;
	import flash.events.Event;
	import flash.events.TimerEvent;
	import flash.geom.Rectangle;
	import flash.utils.Dictionary;
	import flash.utils.setTimeout;
	import flash.utils.Timer;
	import sfb.engines.core.TickManager;
	import com.tomvian.twodee.common.Actor;
	import com.tomvian.maths.Vector2D;
	/**
	 * Shooting
	 * @author Thomas Vian
	 */
	public class Shooting extends Action
	{
		//--------------------------------------------------------------------------
		//
		//  Properties
		//
		//--------------------------------------------------------------------------
		
		public static const DISPLAY_SHOOTING:String = "shooting";
		
		public var screenBounds:Rectangle;
		
		public var targets:Array;
		
		public var hitCallback:Function;
		
		public var bulletClass:Class;
		public var bulletLayer:DisplayObjectContainer;
		public var bulletSpeed:Number;
		public var bulletStart:Vector2D;
		
		public var fireDelay:uint;
		public var finishDelay:uint;
		
		protected var _bullet:Bullet;
		protected var _bullets:Bullet;
		
		protected var _bulletPos:Vector2D;
		
		protected var _fireTimer:Timer;
		protected var _finishTimer:Timer;
		
		//--------------------------------------------------------------------------
		//
		//  Getters / Setters
		//
		//--------------------------------------------------------------------------
		
		//--------------------------------------------------------------------------
		//
		//  Constructor
		//
		//--------------------------------------------------------------------------
		
		public function Shooting(	actor:Actor, 
									screenBounds:Rectangle, 
									targets:Array,
									bulletClass:Class, 
									bulletLayer:DisplayObjectContainer,
									bulletSpeed:Number, 
									bulletStart:Vector2D = null, 
									hitCallback:Function = null,
									fireDelay:uint = 0, 
									finishDelay:uint = 0) 
		{
			super(actor);
			
			this.screenBounds = screenBounds;
			this.targets = targets;
			this.bulletClass = bulletClass;
			this.bulletLayer = bulletLayer;
			this.bulletSpeed = bulletSpeed;
			this.bulletStart = bulletStart || new Vector2D();
			this.hitCallback = hitCallback;
			this.fireDelay = fireDelay;
			this.finishDelay = finishDelay;
			
			_bulletPos = new Vector2D();
			
			_fireTimer = new Timer(fireDelay, 1);
			_fireTimer.addEventListener(TimerEvent.TIMER_COMPLETE, fire);
			_finishTimer = new Timer(finishDelay, 1);
			_finishTimer.addEventListener(TimerEvent.TIMER_COMPLETE, finish);
			
			//TickManager.instance.addTickCall(moveBullets);
		}
		
		//--------------------------------------------------------------------------
		//
		//  Methods
		//
		//--------------------------------------------------------------------------
		
		override public function check(state:uint):void 
		{
			if (actorController.keyPress.shoot && bulletLayer)
			{
				actor.currentAction = this;
			}
		}
		
		override public function start():void 
		{
			actorMass.velocity.x = 0;
			actorMass.velocity.y = 0;
			
			if (fireDelay > 0) 	
			{
				_fireTimer.delay = fireDelay;
				_fireTimer.reset();
				_fireTimer.start();
			}
			else				
			{
				fire();
			}
		}
		
		override public function stop():void 
		{
			_fireTimer.stop();
			_finishTimer.stop();
		}
		
		protected function fire(e:Event = null):void
		{
			var bullet:DisplayObject = new bulletClass();
			bullet.rotation = actor.angle * 180 / Math.PI;
			bulletLayer.addChild(bullet);
			
			var bulletPos:Vector2D = bulletStart.clone();
			bulletPos.rotateMod(actor.angle);
			bulletPos.addMod(actorMass.position);
			bulletPos.setToDO(bullet);
			
			var bulletVel:Vector2D = new Vector2D();
			bulletVel.setFromAngle(actor.angle, bulletSpeed);
			
			_bullet = new Bullet(bullet, bulletPos, bulletVel);
			_bullet.next = _bullets;
			if(_bullets) _bullets.last = _bullet;
			_bullets = _bullet;
			
			if (finishDelay > 0) 	
			{
				_finishTimer.delay = finishDelay;
				_finishTimer.reset();
				_finishTimer.start();
			}
			else					
			{
				finish();
			}
		}
		
		protected function finish(e:Event = null):void
		{
			actor.returnToDefault();
		}
		
		protected function moveBullets():void
		{
			_bullet = _bullets;
			
			while (_bullet)
			{
				_bullet.move();
				
				_bulletPos.copy(_bullet.pos);
				_bulletPos.addMod(cameraOffset);
				
				if (!screenBounds.contains(_bulletPos.x, _bulletPos.y))
				{
					_bullet.remove();
					
					if (_bullet.last) _bullet.last.next = _bullet.next;
					if (_bullet.next) _bullet.next.last = _bullet.last;
					
					if (_bullet == _bullets) _bullets = _bullet.next;
				}
				else
				{
					for (var i:uint = 0, l:uint = targets.length; i < l; i++)
					{
						var target:DisplayObject = targets[i];
						
						if (target.hitTestPoint(_bulletPos.x, _bulletPos.y, true))
						{
							if(Boolean(hitCallback)) hitCallback(target);
							
							_bullet.remove();
							
							if (_bullet.last) _bullet.last.next = _bullet.next;
							if (_bullet.next) _bullet.next.last = _bullet.last;
							
							if (_bullet == _bullets) _bullets = _bullet.next;
						}
					}
				}
				
				_bullet = _bullet.next;
			}
		}
		
		override public function display():void 
		{
			actorState.state = DISPLAY_SHOOTING;
		}
	}
}

import flash.display.DisplayObject;
import com.tomvian.maths.Vector2D;

class Bullet
{
	//--------------------------------------------------------------------------
	//
	//  Properties
	//
	//--------------------------------------------------------------------------
	
	public var graphic:DisplayObject;
	public var pos:Vector2D;
	public var vel:Vector2D;
	
	public var next:Bullet;
	public var last:Bullet;
	
	//--------------------------------------------------------------------------
	//
	//  Constructor
	//
	//--------------------------------------------------------------------------
	
	public function Bullet(graphic:DisplayObject, pos:Vector2D, vel:Vector2D)
	{
		this.graphic = graphic;
		this.pos = pos;
		this.vel = vel;
	}
	
	public function move():void
	{
		pos.addMod(vel);
		pos.setToDO(graphic);
	}
	
	public function remove():void
	{
		if (graphic.parent) graphic.parent.removeChild(graphic);
		
		graphic = null;
	}
}